package com.ylr.base.framework.service.impl;

import com.ylr.base.common.exception.YlrException;
import com.ylr.base.common.po.user.UserPo;
import com.ylr.base.common.utils.UserUtils;
import com.ylr.base.framework.service.AsyncService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.Objects;
import java.util.concurrent.*;
import java.util.function.Supplier;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2023-04-26 21:58:35
 * className: AsyncServiceImpl 异步操作服务接口实现类
 * version: 1.0
 * description:
 *  CompletableFuture异常处理方式：
 *      调用 exceptionally 方法进行异常处理，exceptionally 方法具有幂等性，
 *      同一个 CompletableFuture 对象多次调用 exceptionally 方法，只会执行使用第一次调用内容
 */
public class AsyncServiceImpl implements AsyncService {

    private static final Logger log = LoggerFactory.getLogger(AsyncServiceImpl.class);

    private final String applicationSimpleName;

    private final ThreadPoolTaskExecutor threadPoolTaskExecutor;

    private final ScheduledThreadPoolExecutor scheduledThreadPoolExecutor;

    public AsyncServiceImpl(String applicationSimpleName, ThreadPoolTaskExecutor threadPoolTaskExecutor, ScheduledThreadPoolExecutor scheduledThreadPoolExecutor) {
        this.applicationSimpleName = applicationSimpleName;
        this.threadPoolTaskExecutor = threadPoolTaskExecutor;
        this.scheduledThreadPoolExecutor = scheduledThreadPoolExecutor;
    }

    @Override
    public CompletableFuture<Void> runAsync(Runnable runnable) {
        if (Objects.isNull(threadPoolTaskExecutor)) {
            log.warn("{}模块未实现异步线程池", applicationSimpleName);
            throw new YlrException();
        }
        return CompletableFuture.runAsync(runnable, threadPoolTaskExecutor);
    }

    @Override
    public <V> CompletableFuture<V> supplyAsync(Supplier<V> supplier) {
        if (Objects.isNull(threadPoolTaskExecutor)) {
            log.warn("{}模块未实现异步线程池", applicationSimpleName);
            throw new YlrException();
        }
        return CompletableFuture.supplyAsync(supplier, threadPoolTaskExecutor);
    }

    @Override
    public void schedule(Runnable runnable, long delay, TimeUnit unit) {
        if (Objects.isNull(threadPoolTaskExecutor)) {
            log.warn("{}模块未实现延迟线程池", applicationSimpleName);
            throw new YlrException();
        }
        scheduledThreadPoolExecutor.schedule(runnableDecorator(runnable), delay, unit);
    }

    @Override
    public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
        if (Objects.isNull(threadPoolTaskExecutor)) {
            log.warn("{}模块未实现延迟线程池", applicationSimpleName);
            throw new YlrException();
        }
        return scheduledThreadPoolExecutor.schedule(callableDecorator(callable), delay, unit);
    }

    /**
     * Runnable装饰
     * @param runnable 目标Runnable对象
     * @return 装饰后的Runnable对象
     */
    private Runnable runnableDecorator(Runnable runnable) {
        // 获取调用线程存储的请求用户数据
        UserPo userPo = UserUtils.getUser();
        return () -> {
            try {
                // 设置请求用户
                UserUtils.setUser(userPo);
                // 运行目标线程
                runnable.run();
            } finally {
                // 清理请求用户
                UserUtils.deleteUser();
            }
        };
    }

    /**
     * Callable装饰
     * @param callable 目标Callable对象
     * @return 装饰后的Callable对象
     */
    private <V> Callable<V> callableDecorator(Callable<V> callable) {
        // 获取调用线程存储的请求用户数据
        UserPo userPo = UserUtils.getUser();
        return () -> {
            try {
                // 设置请求用户
                UserUtils.setUser(userPo);
                // 运行目标线程
                return callable.call();
            } finally {
                // 清理请求用户
                UserUtils.deleteUser();
            }
        };
    }
}
